package cc.mrbird.febs.system.service.impl;

import cc.mrbird.febs.common.authentication.JWTUtil;
import cc.mrbird.febs.common.domain.Tree;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.TreeUtil;
import cc.mrbird.febs.system.dao.AreaMapper;
import cc.mrbird.febs.system.dao.THouseMapper;
import cc.mrbird.febs.system.dao.TShopMapper;
import cc.mrbird.febs.system.domain.Area;
import cc.mrbird.febs.system.domain.User;
import cc.mrbird.febs.system.manager.TempInfoManager;
import cc.mrbird.febs.system.service.AreaService;
import cc.mrbird.febs.system.service.ITAreaManagerService;
import cc.mrbird.febs.system.service.ITResidentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dtwei
 */
@Service
public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements AreaService {

    @Resource
    private TShopMapper shopMapper;

    @Resource
    private THouseMapper houseMapper;

    @Resource
    ITAreaManagerService itAreaManagerService;

    @Resource
    ITResidentService itResidentService;

    @Resource
    TempInfoManager tempInfoManager;

    @Override
    public Map<String, Object> findAreas(Area area) {
        Map<String, Object> result = new HashMap<>();
        try {
            List<Area> areas = baseMapper.selectDetails(area);
            List<Tree<Area>> trees = new ArrayList<>();
            List<String> ids = new ArrayList<>();
            buildTrees(trees, areas, ids);

            result.put("ids", ids);
            Tree<Area> menuTree = TreeUtil.build(trees);
            result.put("rows", menuTree);
            result.put("total", areas.size());
        } catch (NumberFormatException e) {
            log.error("查询区域失败", e);
            result.put("rows", null);
            result.put("total", 0);
        }
        return result;
    }

    private void findAreaCondition(LambdaQueryWrapper<Area> queryWrapper, Area area) {
        if (StringUtils.isNotBlank(area.getAreaName())) {
            queryWrapper.like(Area::getAreaName, "%" + area.getAreaName() + "%");
        }
        if (null != area.getLevelNum()) {
            queryWrapper.eq(Area::getLevelNum, area.getLevelNum());
        }
        if (StringUtils.isNotBlank(area.getCreateTimeFrom()) && StringUtils.isNotBlank(area.getCreateTimeTo())) {
            queryWrapper
                    .ge(Area::getCreateTime, area.getCreateTimeFrom())
                    .le(Area::getCreateTime, area.getCreateTimeTo());
        }
    }

    private void buildTrees(List<Tree<Area>> trees, List<Area> areas, List<String> ids) {
        areas.forEach(area -> {
            ids.add(area.getAreaId().toString());
            Tree<Area> tree = new Tree<>();
            tree.setId(area.getAreaId().toString());
            tree.setKey(tree.getId());
            tree.setParentId(area.getParentId().toString());
            tree.setText(area.getAreaName());
            tree.setTitle(area.getAreaName());
            tree.setValue(area.getLevelNum().toString());
            tree.setCreateTime(area.getCreateTime());
            tree.setModifyTime(area.getModifyTime());
            tree.setOrder(area.getOrderNum());
            tree.setResidents(area.getResidents());
            trees.add(tree);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createArea(Area area) throws Exception{
        //获取当前用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        String userId = "";
        if (StringUtils.isNotBlank(token)) {
            username = JWTUtil.getUsername(token);
            userId = JWTUtil.getUserId(token);
        }
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Area::getAreaName, area.getAreaName());
        List<Area> dupAreas = baseMapper.selectList(queryWrapper);
        if(dupAreas != null && dupAreas.size() >= 1) {
            String message = "新增区域失败：区域名称重复";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }

        if (area.getParentId() == null) {
            area.setParentId(0L);
            area.setLevelNum(1);
        }

        //是否存在父区域
        if (area.getParentId() != 0) {
            LambdaQueryWrapper<Area> queryWrapper2 = new LambdaQueryWrapper<>();
            queryWrapper2.eq(Area::getAreaId, area.getParentId());
            Area parArea = baseMapper.selectOne(queryWrapper2);
            if(parArea == null) {
                String message = "新增区域失败：父区域不存在";
                Exception e = new FebsException(message);
                log.error(message, e);
                throw e;
            }
            area.setLevelNum(parArea.getLevelNum() + 1);
        }

        area.setCreateTime(new Date());
        area.setCreateUsername(username);
        area.setCreateUserId(Long.valueOf(userId));
        this.baseMapper.insertArea(area);

        if(null != area.getResidents() && area.getResidents().size() > 0 && null != area.getAreaId()) {
            //判断网格管理员是否存在
            int rsCount = itResidentService.countResidents(area.getResidents());
            if(rsCount != area.getResidents().size()) {
                String message = "新增区域失败：网格管理员不存在";
                Exception e = new FebsException(message);
                log.error(message, e);
                throw e;
            }
            //删除后新增
            itAreaManagerService.updateAfterDelAreaManager(area.getAreaId(), area.getResidents());
        }
    }

    @Override
    public void deleteAreas(String[] areaIds) throws Exception {
        //关联表含有数据不能删除
        //商铺
        int shopCount = shopMapper.countShopByAreaIds(Arrays.asList(areaIds));
        if(shopCount > 0) {
            String message = "删除区域失败：存在关联商铺，请先删除关联商铺";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }
        //住宅
        int houseCount = houseMapper.coundHouseByAreaIds(Arrays.asList(areaIds));
        if(houseCount > 0) {
            String message = "删除区域失败：存在关联住宅，请先删除关联住宅";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }
        this.delete(Arrays.asList(areaIds));
    }

    @Override
    @Transactional
    public void updateArea(Area area) throws Exception {
        //获取当前用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        String userId = "";
        if (StringUtils.isNotBlank(token)) {
            username = JWTUtil.getUsername(token);
            userId = JWTUtil.getUserId(token);
        }

        Area tempArea = getById(area.getAreaId());
        if(tempArea == null) {
            String message = "更新区域失败：区域不存在";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }
        if(this.checkDup(area.getAreaName(), area.getAreaId())) {
            String message = "更新区域失败：区域名称重复";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }

        //树结构校验
        if (null != area.getParentId() && area.getParentId() != 0) {
            LambdaQueryWrapper<Area> queryWrapper2 = new LambdaQueryWrapper<>();
            queryWrapper2.eq(Area::getAreaId, area.getParentId());
            Area parArea = baseMapper.selectOne(queryWrapper2);
            if(parArea == null) {
                String message = "新增区域失败：父区域不存在";
                Exception e = new FebsException(message);
                log.error(message, e);
                throw e;
            }
            area.setLevelNum(parArea.getLevelNum() + 1);

            //父节点是否为其子节点
            LambdaQueryWrapper<Area> queryWrapper3 = new LambdaQueryWrapper<>();
            queryWrapper3.eq(Area::getParentId, area.getAreaId());
            List<Area> childAreas = this.baseMapper.selectList(queryWrapper3);
            if(null != childAreas && childAreas.size() > 0) {
                List<Long> childIds = childAreas.stream().map(Area::getAreaId).collect(Collectors.toList());
                if (childIds.contains(area.getParentId())) {
                    String message = "新增区域失败：父区域为当前区域的子区域";
                    Exception e = new FebsException(message);
                    log.error(message, e);
                    throw e;
                }
            }
        } else {
            area.setParentId(0L);
            area.setLevelNum(1);
        }

        UpdateWrapper<Area> upWrp = new UpdateWrapper<>();
        upWrp.set("AREA_NAME", area.getAreaName());
        upWrp.set("PARENT_ID", area.getParentId());
        upWrp.set("LEVEL_NUM", area.getLevelNum());
        upWrp.set("ORDER_NUM", area.getOrderNum());
        upWrp.set("MODIFY_TIME", new Date());
        upWrp.set("MODIFY_USERNAME", username);
        upWrp.set("MODIFY_USER_ID", userId);
        upWrp.eq("AREA_ID",area.getAreaId());
        this.baseMapper.update(null, upWrp);

        if(null != area.getResidents() && area.getResidents().size() > 0 && null != area.getAreaId()) {
            //判断网格管理员是否存在
            int rsCount = itResidentService.countResidents(area.getResidents());
            if(rsCount != area.getResidents().size()) {
                String message = "新增区域失败：网格管理员不存在";
                Exception e = new FebsException(message);
                log.error(message, e);
                throw e;
            }
            //删除后新增
            itAreaManagerService.updateAfterDelAreaManager(area.getAreaId(), area.getResidents());
        }
    }

    @Override
    public List<Area> findAreaList(Area area) {
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        findAreaCondition(queryWrapper, area);
        queryWrapper.orderByAsc(Area::getAreaId);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<Area> findAllAreaList() {
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        List<Area> areas = this.baseMapper.selectList(queryWrapper);
        if(null != areas && areas.size() > 0) {
            try {
                tempInfoManager.loadAllAreaRedisCache(areas);
            } catch (Exception e) {
                log.error("redis error：", e);
            }
        }
        return areas;
    }

    private boolean checkDup(String areaName, Long areaId) {
        QueryWrapper<Area> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().ne(Area::getAreaId, areaId).eq(Area::getAreaName, areaName);
        List<Area> ret = this.baseMapper.selectList(queryWrapper);
        return (null != ret && ret.size() >= 1);
    }

    private void delete(List<String> areaIds) {
        //删除区域
        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Area::getParentId, areaIds);
        List<Area> areas = baseMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(areas)) {
            List<String> areaIdList = new ArrayList<>();
            areas.forEach(m -> areaIdList.add(String.valueOf(m.getAreaId())));
            this.delete(areaIdList);
        }
        removeByIds(areaIds);

        //删除区域管理员
        itAreaManagerService.deleteByAreaId(areaIds);
    }
}
